`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2020/10/29 20:16:14
// Design Name: 
// Module Name: axi_ctrl
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module axi_ctrl(
    input               clk,
    input               rst_n,

    //! pl_para
    input               trigger,
    input       [2:0]   intr_state,
    input       [31:0]  pl_cnt,
    input       [31:0]  pl_adr,

    //! axi_maser
    output reg          wr_start,
    output      [31:0]  wr_adrs,
    output      [31:0]  wr_len,
    input               wr_ready,
    input               wr_done,

    //! fifo
    input       [12:0]  fifo_rd_data_count
    );
localparam  S_IDLE      = 4'd0;
localparam  S_SWITCH    = 4'd1;
localparam  S_WAIT_FIFO = 4'd2;
localparam  S_WAIT_AXI  = 4'd3;
localparam  S_UP_PARA   = 4'd4;
localparam  S_ALL_OUT   = 4'd5;
localparam  S_WAIT_DONE = 4'd6;
localparam  S_DONE      = 4'd7;

reg [4:0]   state;

reg [31:0]  reg_cnt;
reg [31:0]  reg_adr;
reg [31:0]  cur_cnt;

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        //TODO 清零
    end else begin
        case (state)
            S_IDLE: begin
                wr_start    <= 0;
                reg_cnt     <= 0;
                reg_adr     <= 0;
                cur_cnt     <= 0;
                if (trigger) begin
                    state       <= S_SWITCH;
                    reg_cnt     <= pl_cnt;
                    reg_adr     <= pl_adr;
                end else begin
                    state       <= S_IDLE;
                end
            end
            S_SWITCH: begin
                wr_start    <= 0;
                if (reg_cnt > 32'd2048) begin
                    cur_cnt <= 32'd1024;
                    state   <= S_WAIT_FIFO;
                end else begin
                    cur_cnt <= reg_cnt;
                    state   <= S_ALL_OUT;
                end
            end
            S_WAIT_FIFO: begin
                wr_start    <= 0;
                if (wr_ready & (fifo_rd_data_count > 32'd1024)) begin
                    state       <= S_WAIT_AXI;
                    wr_start    <= 1;
                end else begin
                    state   <= S_WAIT_FIFO;
                end
            end
            S_WAIT_AXI: begin
                wr_start    <= 0;
                if (wr_done) begin
                    state   <= S_UP_PARA;
                end else begin
                    state   <= S_WAIT_AXI;
                end
            end
            S_UP_PARA: begin
                wr_start    <= 0;
                reg_adr     <= reg_adr + 32'd8192;
                reg_cnt     <= reg_cnt - 1024;
                state       <= S_SWITCH;
            end
            S_ALL_OUT: begin
                wr_start    <= 0;
                if (intr_state > 3'd1) begin
                    state       <= S_WAIT_DONE;
                    wr_start    <= 1;
                end else begin
                    state       <= S_ALL_OUT;
                end
            end
            S_WAIT_DONE: begin
                wr_start    <= 0;
                if (wr_done) begin
                    state  <= S_DONE;
                end else begin
                    state  <= S_WAIT_DONE;
                end
            end
            S_DONE: begin
                wr_start    <= 0;
                state  <= S_IDLE;
            end
            default: begin
                state  <= S_IDLE;
            end
        endcase
    end
end

assign  wr_adrs[31:0]   = reg_adr[31:0];
assign  wr_len[31:0]    = cur_cnt[31:0];

endmodule
